import ProtocolMessage from "../../model/protocol/ProtocolMessage";
import IApi from "./IApi";
import { echatIMSDK } from "../sdk/EChatIMSDK";
import ApiResponse from "./ApiResponse";
import Beans from "../../common/utils";
import R from "../../model/protocol/R";
import { jwtCache } from "../cache/jwt";
import UserLoginForm from "../../model/form/UserLoginForm";
import EChatIMApis from "./EChatIMApis";
import Logger from "../../log/Logger";
import Fetch from "../fileclient/support/Fetch";


export default class HttpApi<K extends ProtocolMessage, V> implements IApi<K,V> {
    url: string;
    name: string | undefined;
    needAuth: boolean | undefined;
    method: string | undefined;


    constructor(url = "", name: string, method?:string, needAuth?: boolean) {
        this.url = url;
        this.name = name;
        this.needAuth = needAuth;
        this.method = method;
    }


    call(params?: K): Promise<ApiResponse<V>> {
        if(params === undefined){
            params = new ProtocolMessage() as K;
        }

        let url = 'http://' + this.getHost() + ':' +  this.getPort() +  (this.url.startsWith("/") ? this.url : "/" + this.url);
        let requestMethod = this.method === undefined ? 'POST' : this.method;


        // 使用数字签名
        if(this.needAuth && !jwtCache.jwt){
            let self = this;
            return new Promise<ApiResponse<V>>(function (resolve, reject) {
                const form = new UserLoginForm();
                form.auid = echatIMSDK.getState().loginAuid;
                form.token = echatIMSDK.getState().loginToken;
                form.appKey = echatIMSDK.getState().key;
                const tokenResponse: Promise<ApiResponse<string>> = EChatIMApis.login.call(form);
                tokenResponse.then((res) => {
                    // resolve(res);
                    if(res.isSucceed()){
                        if(!res.data){
                            throw Error('server not return jwt yet.');
                        }
                        jwtCache.jwt = res.data!.toString();
                        // return res.data.data;
                        // re-call again
                        const apiResponse: Promise<ApiResponse<K>> = self.call(params);
                        apiResponse.then((res) => {
                            resolve(res);
                        }).catch(e => {
                            reject(e);
                        })
                    }
                    else {
                        throw Error('get jwt failed.');
                    }

                }).catch((e) =>{
                    Logger.info(`auto login failed, url=${self.url}`);
                    reject(e);
                })
            });
        }
        console.log(`==> [${requestMethod}] ${url} call with params:` + Beans.json(params));
        const headers = {
            'Content-Type':'application/json',
            'Request-Id':new Date().getTime() + '' + parseInt(Math.random() * 1000 + ''),
            'authorization':'client ' + jwtCache.jwt,
            'timestamp':new Date().getTime(),
        };
        // const request: any = {method: requestMethod, body: params};
        const request: any = {method: requestMethod, mode: 'cors', headers:headers, body: Beans.json(params)};
        return this.httpFetch(url, request);

    }



    public response2ApiResponse( response: R<V>): ApiResponse<V> {
        const apiResponse: ApiResponse<V> = new ApiResponse<V>(true);
        apiResponse.data = response.data;
        apiResponse.errorCode = response.code;
        apiResponse.errorMessage = response.msg;
        apiResponse.raw = response ? Beans.json(response) : '';

        return apiResponse;
    }


    getHost: () => string = function(){
        return echatIMSDK.getState().host;
    }
    getPort: () => number = function(){
        return echatIMSDK.getState().httpPort;
    }



    private httpFetch(url:string, request:any):Promise<ApiResponse<V>>{
        /*IFTRUE_WXAPP*/
        // @ts-ignore
        if(wx === undefined){
            throw new Error('wx handle not exist');
        }
        return new Promise<ApiResponse<V>>(function (resolve, reject) {
            // @ts-ignore
            wx.request({
                method: request.method,
                url: url, //仅为示例，并非真实的接口地址
                data: Beans.bean(request.body),
                header: request.headers,
                success (res) {
                    // console.log(res.data)
                    resolve(res.data);
                },
                fail(res){
                    // console.error(res.data)
                    reject(res.data);
                }
            });
        });
        /*FITRUE_WXAPP*/

        /*IFTRUE_WEBAPP*/
        let webfetch = Fetch.getFetchToolkit();
        return webfetch(url as string, request).then(response =>{
            return response.json();
        }).then(res =>{
            console.log(`==> [${request.method}] ${url} back:` + Beans.json(res));
            const resp = this.response2ApiResponse(res);
            if(resp.isFailed()){
                // return Promise.reject(new Error(Beans.json(resp)));
                return Promise.reject(resp);
            }
            return Promise.resolve(this.response2ApiResponse(res));
        });
        /*FITRUE_WEBAPP*/

        /*IFTRUE_RNAPP*/
        let rnfetch = Fetch.getFetchToolkit();
        return rnfetch(url as string, request).then(response =>{
            return response.json();
        }).then(res =>{
            console.log(`==> [${request.method}] ${url} back:` + Beans.json(res));
            const resp = this.response2ApiResponse(res);
            if(resp.isFailed()){
                // return Promise.reject(new Error(Beans.json(resp)));
                return Promise.reject(resp);
            }
            return Promise.resolve(this.response2ApiResponse(res));
        });
        /*FITRUE_RNAPP*/
    }
}
